
//3
// enum List1 {
//     Cons(i32, Box<List1>),
//     Nil,
// }
// use crate::List1::{Cons,Nil};

// fn try_cons_box_list(){
//     let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
// }

//2
//enum List {
//     Cons(i32, List),
//     Nil,
// }
// use crate::List::{Cons,Nil};
// fn try_cons_list(){
//     let list = Cons(1, Cons(2, Cons(3, Nil)));
// }


//1
// fn try_box(){
//     let b = Box::new(5);
//     println!("b={b}");
//     println!("{}", *b);
//     // let c = b;
//     // println!("c={c}");
//     // println!("b={b}");
// }

//4
// fn try_track_pointer(){
//     let x = 5;
//     let y = &x;
//     assert_eq!(5,x);
//     assert_eq!(5,*y);
// }

//5
// fn try_track_box(){
//     let x = 5;
//     let y = Box::new(5);
//     assert_eq!(5,x);
//     assert_eq!(5,*y);
// }

use std::{cell::RefCell, ops::Deref, rc::{Rc, Weak}};

//6
// struct MyBox<T>(T);
// impl<T> MyBox<T> {
//     fn new(x:T) -> MyBox<T> {
//         MyBox(x)
//     }
// }
// impl <T> Deref for MyBox<T> {
//     type Target = T;

//     fn deref(&self) -> &Self::Target {
//         &self.0
//     }
// }

// fn hello(name: &str) {
//     println!("Hello, {name}!");
// }

// fn try_custom_ref(){
//     let x = 5;
//     let y = MyBox::new(5);
//     assert_eq!(x, 5);
//     assert_eq!(5, *y);
    
//     let str = String::from("123");
//     hello(&str);

//     hello(&MyBox::new(String::from("Rust")));
// }


//7
// struct CustomSmartPointer{
//     data: String,
// }

// impl Drop for CustomSmartPointer {
//     fn drop(&mut self) {
//         println!("Dropping CustomSmartPointer with data `{}`!", self.data);
//     }
// }

// fn try_drop_function(){
//     let c = CustomSmartPointer{
//         data: String::from("my stuff"),
//     };
//     let d = CustomSmartPointer{
//         data: String::from("other stuff"),
//     };
//     //d.drop();
//     drop(d);
//     println!("CustomSmartPointers created.");
// }


//8
// enum List {
//     Cons(i32, Box<List>),
//     Nil,
// }
// use crate::List::{Cons, Nil};

// fn try_mult_owner(){
//     let a = Cons(5, Box::new(Cons(10, Box::new(Nil))));
//     let b = Cons(3, Box::new(a));
//     let c = Cons(4, Box::new(a));
// }


//9
// enum List {
//     Cons(i32, Rc<List>),
//     Nil,
// }

// use crate::List::{Cons, Nil};

// fn try_rc_function(){
//     let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil)))));
//     println!("count after creating a ={}", Rc::strong_count(&a));
//     let b = Cons(3, Rc::clone(&a));
//     println!("count after creating b={}", Rc::strong_count(&a));
//     {
//         let c = Cons(4, Rc::clone(&a));
//         println!("count after creating c={}", Rc::strong_count(&a));
//     }
//     println!("count after c goes out of scop = {}", Rc::strong_count(&a));
// }


//10
// pub trait Messenger {
//     fn send(&self, msg: &str);
// }

// pub struct LimitTracker<'a, T: Messenger> {
//     messenger: &'a T,
//     value: usize,
//     max: usize,
// }

// impl <'a, T> LimitTracker<'a, T> 
// where 
//     T: Messenger,
// {
//     pub fn new(messenger: &'a T, max: usize) -> LimitTracker<'a, T> {
//         LimitTracker{
//             messenger, 
//             value: 0,
//             max,
//         }
//     }

//     pub fn set_value(&mut self, value: usize) {
//         self.value = value;
//         let percentage_of_max = self.value as f64 / self.max as f64;

//         if percentage_of_max >= 1.0 {
//             self.messenger.send("Error: You are over you quota!");
//         }else if percentage_of_max >= 0.9 {
//             self.messenger.send("Urgent warning: You've used up over 90% of your quota!");
//         }else if percentage_of_max >= 0.75{
//             self.messenger.send("Warning: You've used up over 75% of your quota!");
//         }
//     }
// }

// struct MockMessenger{
//     // sent_messages: Vec<String>,
//     sent_messages: RefCell<Vec<String>>,
// }

// impl MockMessenger {
//     fn new() -> MockMessenger {
//         MockMessenger{
//             //sent_messages: vec![],
//             sent_messages: RefCell::new(vec![]),
//         }
//     }
// }

// impl Messenger for MockMessenger {
//     fn send(&self, msg: &str) {
//         //self.sent_messages.push(String::from(msg));
//         self.sent_messages.borrow_mut().push(String::from(msg));
//         // let mut_borrow1 = self.sent_messages.borrow_mut();
//         // let mut_borrow2 = self.sent_messages.borrow_mut();
//         // mut_borrow1.push(String::from("a"));
//         // mut_borrow2.push(String::from("b"));
//     }
// }

// fn try_refcall_function(){
//     let mock_messenger = MockMessenger::new();
//     let mut limit_tracker = LimitTracker::new(&mock_messenger, 100);
//     limit_tracker.set_value(80);
//     //assert_eq!(mock_messenger.sent_messages.len(), 1);
//     println!("{}", mock_messenger.sent_messages.borrow()[0]);
//     println!("{}", mock_messenger.sent_messages.borrow().get(0).unwrap());
//     println!("{}", mock_messenger.sent_messages.borrow().len());
//     assert_eq!(mock_messenger.sent_messages.borrow().len(), 1);
// }


//11
// #[derive(Debug)]
// enum List {
//     Cons(Rc<RefCell<i32>>, Rc<List>),
//     Nil,
// }

// use crate::List::{Cons, Nil};

// fn try_rec_reccell_function(){
//     let value = Rc::new(RefCell::new(5));
//     let a = Rc::new(Cons(Rc::clone(&value), Rc::new(Nil)));
//     let b = Cons(Rc::new(RefCell::new(3)), Rc::clone(&a));
//     let c = Cons(Rc::new(RefCell::new(4)), Rc::clone(&a));

//     *value.borrow_mut()+=10;

//     println!("a after = {a:?}");
//     println!("b after = {b:?}");
//     println!("c after = {c:?}");
    
// }

//12
// #[derive(Debug)]
// enum List {
//     Cons(i32, RefCell<Rc<List>>),
//     Nil,
// }

// use crate::List::{Cons, Nil};

// impl List {
//     fn tail(&self) -> Option<&RefCell<Rc<List>>>{
//         match self {
//             Cons(_, item) => Some(item),
//             Nil => None,
//         }
//     }
// }

// fn try_loop_ref(){
//     let a = Rc::new(Cons(5, RefCell::new(Rc::new(Nil))));
//     print!("a initial rc count={}", Rc::strong_count(&a));
//     println!("a next item = {:?}", a.tail());

//     let b = Rc::new(Cons(10, RefCell::new(Rc::clone(&a))));

//     println!("a rc count after b creation = {}", Rc::strong_count(&a));
//     println!("b initial rc count = {}", Rc::strong_count(&b));
//     println!("b next item = {:?}", b.tail());

//     if let Some(link) = a.tail(){
//         *link.borrow_mut() = Rc::clone(&b);
//     }

//     println!("b rc count after changing a = {}", Rc::strong_count(&b));
//     println!("a rc count after changing a = {}", Rc::strong_count(&a));

//     // Uncomment the next line to see that we have a cycle;
//     // it will overflow the stack
//     //println!("a next item = {:?}", a.tail());
// }

//13
// #[derive(Debug)]
// struct Node{
//     value: i32,
//     children: RefCell<Vec<Rc<Node>>>,
// }

// fn try_tree_node(){
//     let leaf = Rc::new(Node{value:3, children: RefCell::new(vec![])});
//     let branch = Rc::new(Node{value:5, children: RefCell::new(vec![Rc::clone(&leaf)])});
// }


//14
// #[derive(Debug)]
// struct Node{
//     value: i32,
//     parent: RefCell<Weak<Node>>,
//     children: RefCell<Vec<Rc<Node>>>,
// }

// fn try_two_way_tree(){
//     let leaf = Rc::new(Node{
//         value: 3,
//         parent: RefCell::new(Weak::new()),
//         children: RefCell::new(vec![]),
//     });
    
//     println!("leaf parent={:?}", leaf.parent.borrow().upgrade());

//     let branch = Rc::new(Node{
//         value: 5,
//         parent: RefCell::new(Weak::new()),
//         children: RefCell::new(vec![Rc::clone(&leaf)]),
//     });

//     *leaf.parent.borrow_mut() = Rc::downgrade(&branch);

//     println!("leaf parent = {:?}", leaf.parent.borrow().upgrade());
// }

//15
#[derive(Debug)]
struct Node{
    value: i32,
    parent: RefCell<Weak<Node>>,
    children: RefCell<Vec<Rc<Node>>>,
}

fn try_two_way_tree_print_strong_weak_count(){
    let leaf = Rc::new(Node{
        value: 3,
        parent: RefCell::new(Weak::new()),
        children: RefCell::new(vec![]),
    });
    
    println!("leaf strong = {}, weak = {}", Rc::strong_count(&leaf), Rc::weak_count(&leaf),);

    {
        let branch = Rc::new(Node{
            value: 5,
            parent: RefCell::new(Weak::new()),
            children: RefCell::new(vec![Rc::clone(&leaf)]),
        });

        *leaf.parent.borrow_mut() = Rc::downgrade(&branch);
        
        println!("branch strong = {}, weak = {}", Rc::strong_count(&branch), Rc::weak_count(&branch),);
        println!("leaf strong = {}, weak = {}", Rc::strong_count(&leaf), Rc::weak_count(&leaf),);
    }
    println!("leaf parent = {:?}", leaf.parent.borrow().upgrade());
    println!("leaf strong = {}, weak = {}", Rc::strong_count(&leaf), Rc::weak_count(&leaf),);

}

fn main() {
    //1
    //try_box();
    //2
    //try_cons_list();
    //3
    //try_cons_box_list();
    //4
    //try_track_pointer();
    //5
    //try_track_box();
    //6
    //try_custom_ref();
    //7
    //try_drop_function();
    //8
    //try_mult_owner();
    //9
    //try_rc_function();
    //10
    //try_refcall_function();
    //11
    //try_rec_reccell_function();
    //12
    //try_loop_ref();
    //14
    //try_two_way_tree();
    //15
    try_two_way_tree_print_strong_weak_count();
}
